package com.zonski.jbots.engine;

import java.util.Vector;

/**
 * Base class for all entities in the game
 */
public class Entity
{
    /**
     * Indicates the number of 'steps' that an entity 
     * starts with at the start of the turn, this is used
     * to work out distances travelled after collisions
     */
    public static final int STARTING_STEPS = 128;
    public Rectangle bounds;
    public int layerId;
    /**
     * Renderer for this entity, because the platforms on which
     * this entity will be rendered vary, this object does not
     * share an interface. May be null
     */
    public Object renderer;

    public CollisionEffect collisionEffect;
    public EntityType entityType;
    public int direction;
    public int xVelocity;
    public int yVelocity;
    /**
     * The speed at which this entity is turning (if any)
     */
    public int turnVelocity;
    /**
     * The steps remaining on this turn that haven't been used up in collisions
     */
    public int stepsRemaining;

    private int mode;
    private int effectiveMode;
    public int effectiveModeUpdates;
    private boolean removable;
    private QuickVector resources;
    private Device device;

    private int charge;
    private int maxCharge;

    public Entity()
    {
    }

    public final Device getDevice()
    {
        return this.device;
    }

    public final void setDevice(Device device)
    {
        this.device = device;
    }

    public int getMode()
    {
        return this.mode;
    }

    public void setMode(int mode)
    {
        this.mode = mode;
    }


    public int getCharge()
    {
        return this.charge;
    }

    public void setCharge(int charge)
    {
        if(charge > this.maxCharge)
        {
            charge = this.maxCharge;
        }
        this.charge = charge;
        if(this.charge <= 0 && this.maxCharge > 0)
        {
            //this.setRemovable(true);
            this.setMode(Modes.DEAD);
            this.setEffectiveMode(Modes.DEAD);
        }
    }

    public int getMaxCharge()
    {
        return maxCharge;
    }

    public void setMaxCharge(int maxCharge)
    {
        this.maxCharge = maxCharge;
    }

    public final int getEffectiveMode()
    {
        return this.effectiveMode;
    }

    public final void setEffectiveMode(int effectiveMode)
    {
        if(this.effectiveMode != effectiveMode)
        {
            this.effectiveModeUpdates = 0;
            this.effectiveMode = effectiveMode;
        }
    }


    /**
     * The number of times the entity has been updated in
     * it's current mode
     */
    public int getEffectiveModeUpdates()
    {
        return this.effectiveModeUpdates;
    }

    public final CollisionEffect getCollisionEffect()
    {
        return this.collisionEffect;
    }

    public final void setCollisionEffect(CollisionEffect collisionEffect)
    {
        this.collisionEffect = collisionEffect;
    }

    /**
     * Updates the entity
     */
    public void update(Engine engine)
        throws Exception
    {
        this.effectiveModeUpdates++;
        this.stepsRemaining = STARTING_STEPS;
        // update the resources
        /*
        if(this.resources != null)
        {
            for(int i=resources.size(); i>0; )
            {
                i--;
                Resource resource = (Resource)resources.elementAt(i);
                resource.update(engine);
            }
        }
        */
    }

    /**
     * Indicates that the entity has had a collision and should react
     * @return whether the entity has changed as a result of this
     * collision, if it hasn't then the new position and velocity
     * of the entity does not need to be calculated and checked for
     * collisions
     */
    public boolean collision(Engine engine, CollisionData data)
    {
        if(collisionEffect != null)
        {
            return collisionEffect.apply(this, engine, data);
        }else{
            return false;
        }
    }

    public final void setVelocity(int xVelocity, int yVelocity,
            int turnVelocity)
    {
        this.setVelocity(xVelocity, yVelocity, turnVelocity, STARTING_STEPS);
    }

    public final void setVelocity(int xVelocity, int yVelocity, 
            int turnVelocity, int stepsRemaining)
    {
        this.xVelocity = xVelocity;
        this.yVelocity = yVelocity;
        this.turnVelocity = turnVelocity;
        this.stepsRemaining = stepsRemaining;
    }

    public boolean isRemovable()
    {
        return this.removable;
    }

    public void setRemovable(boolean removable)
    {
        this.removable = removable;
        if(removable && this.resources != null)
        {
            for(int i=this.resources.size(); i>0; )
            {
                i--;
                Resource resource = (Resource)this.resources.elementAt(i);
                if(resource instanceof UsableResource)
                {
                    ((UsableResource)resource).stopUsing();
                }
            }
        }
    }

    public Resource getResource(String application)
    {
        Resource resource;
        int index = this.getResourceIndex(application);
        if(index >= 0)
        {
            resource = (Resource)this.resources.elementAt(index);
        }else{
            resource = null;
        }
        return resource;
    }

    public void setResource(String application, Resource resource)
    {
        if(this.resources == null)
        {
            this.resources = new QuickVector(4);
        }
        resource.setOwner(this, application);
        // see if there is a resource with the same application, if
        // so get rid of it
        int index = getResourceIndex(application);
        if(index >=0)
        {
            this.resources.removeElementAt(index);
        }
        this.resources.addElement(resource);
    }

    public QuickVector getResources()
    {
        return this.resources;
    }

    private int getResourceIndex(String application)
    {
        int index;
        if(this.resources != null)
        {
            index = -1;
            for(int i=this.resources.size(); i>0; )
            {
                i--;
                Resource resource = (Resource)this.resources.elementAt(i);
                if(resource.getApplication().equals(application))
                {
                    index = i;
                    break;
                }
            }
        }else{
            index = -1;
        }
        return index;
    }
}
